package com.demo.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author chenyuan
 * @date 2020/9/23 20:47
 */
@Configuration
public class ShiroConfig {

    //三大要素
    //实际操作中对象创建的顺序 ： realm -> securityManager -> subject

//1. subject -> ShiroFilterFactoryBean
    // @Qualifier("securityManager") 指定 Bean 的名字为 securityManager
    // 拦截所有请求

    @Bean(name = "shiroFilterFactoryBean")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("SecurityManager") DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean subject = new ShiroFilterFactoryBean();
        //设置安全管理器
        //需要关联 securityManager ，通过参数把 securityManager 对象传递过来
        subject.setSecurityManager(securityManager);

        //添加 Shiro 的内置过滤器
        /*
            anon : 无需认证，就可以访问
            authc : 必须认证，才能访问
            user : 必须拥有 “记住我”功能才能用
            perms : 拥有对某个资源的权限才能访问
            role : 拥有某个角色权限才能访问
         */
        Map<String, String> map = new LinkedHashMap<>();
        // 设置 /user/addUser 这个请求,只有认证过才能访问
//        map.put("/user/addUser","authc");
//        map.put("/user/deleteUser","authc");

        // 设置不受限的资源
        map.put("/login","anon");
        map.put("/tologin","anon");
        map.put("/register","anon");
        map.put("/toregister","anon");
        map.put("/logout","anon");

        // 设置所有请求,只有认证过才能访问
        map.put("/**","anon");

        subject.setFilterChainDefinitionMap(map);

        // 设置登录的请求
        subject.setLoginUrl("/tologin");
        return subject;
    }

    //2. securityManager -> DefaultWebSecurityManager
    // @Qualifier("userRealm") 指定 Bean 的名字为 userRealm
    // spring 默认的 BeanName 就是方法名
    // name 属性 指定 BeanName

    @Bean(name = "SecurityManager")
    public DefaultWebSecurityManager getDefaultWebSecurity(@Qualifier("userRealm") UserRealm userRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //需要关联自定义的 Realm，通过参数把 Realm 对象传递过来
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    //3. realm
    //让 spring 托管自定义的 realm 类

    @Bean
    public UserRealm userRealm(){
        UserRealm realm = new UserRealm();
//==密码加密================
        // 新建 HashedCredentialsMatcher 凭证匹配器
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        // 指定算法的名字
        credentialsMatcher.setHashAlgorithmName("md5");
        // 指定散列的次数
        credentialsMatcher.setHashIterations(1024);
        // 把 HashedCredentialsMatcher 存入 Realm
        realm.setCredentialsMatcher(credentialsMatcher);
//==========================

// ===开启缓存===============
        // 开启 EhCache 缓存管理
        realm.setCacheManager(new EhCacheManager());
        // 开启全局缓存管理
        realm.setCachingEnabled(true);
        // 开启授权的缓存管理
        realm.setAuthorizationCachingEnabled(true);
        // 指定授权缓存的名字，默认为 当前方法名+Authorization
        realm.setAuthorizationCacheName("authorizationCache");
        // 开启认证的缓存管理
        realm.setAuthenticationCachingEnabled(true);
        realm.setAuthenticationCacheName("authenticationCache");



        return realm;
    }

    // Shiro 在 html 页面上方言配置

    @Bean(name="shiroDialect")
    public ShiroDialect shiroDialect(){
        return new ShiroDialect();
    }

}
